package com.mall.mymall.service.impl;

import com.mall.mymall.dao.entity.UserBehavior;
import com.mall.mymall.dao.entity.UserSimilarity;
import com.mall.mymall.mapper.UserBehaviorMapper;
import com.mall.mymall.mapper.UserSimilarityMapper;
import com.mall.mymall.service.UserSimilarityService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 十里坡
 * @since 2025-03-14
 */
@Service
public class UserSimilarityServiceImpl extends ServiceImpl<UserSimilarityMapper, UserSimilarity> implements UserSimilarityService {

    @Autowired
    private UserBehaviorMapper userBehaviorMapper;

    public Map<Integer, Map<Integer, Double>> calculateUserSimilarity() {
        List<UserBehavior> userBehaviors = userBehaviorMapper.selectList(null);

        // 用户-商品评分矩阵
        Map<Integer, Map<Integer, BigDecimal>> userItemMatrix = new HashMap<>();
        for (UserBehavior behavior : userBehaviors) {
            userItemMatrix.computeIfAbsent(behavior.getUserId(), k -> new HashMap<>())
                    .put(behavior.getProductId(), behavior.getBehaviorValue());
        }

        // 用户相似度矩阵
        Map<Integer, Map<Integer, Double>> userSimilarityMatrix = new HashMap<>();

        // 计算用户之间的相似度
        List<Integer> userIds = new ArrayList<>(userItemMatrix.keySet());
        for (int i = 0; i < userIds.size(); i++) {
            for (int j = i + 1; j < userIds.size(); j++) {
                Integer user1 = userIds.get(i);
                Integer user2 = userIds.get(j);

                double similarity = cosineSimilarity(userItemMatrix.get(user1), userItemMatrix.get(user2));
                userSimilarityMatrix.computeIfAbsent(user1, k -> new HashMap<>()).put(user2, similarity);
                userSimilarityMatrix.computeIfAbsent(user2, k -> new HashMap<>()).put(user1, similarity);
            }
        }

        return userSimilarityMatrix;
    }

    private double cosineSimilarity(Map<Integer, BigDecimal> user1, Map<Integer, BigDecimal> user2) {
        Set<Integer> commonItems = user1.keySet().stream().filter(user2::containsKey).collect(Collectors.toSet());
        if (commonItems.isEmpty()) {
            return 0.0;
        }

        double dotProduct = 0.0;
        double norm1 = 0.0;
        double norm2 = 0.0;

        for (Integer item : commonItems) {
            dotProduct += user1.get(item).doubleValue() * user2.get(item).doubleValue();
            norm1 += Math.pow(user1.get(item).doubleValue(), 2);
            norm2 += Math.pow(user2.get(item).doubleValue(), 2);
        }

        return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
    }
}
